
namespace MaterialSkin.Controls
{

    using System;
    using System.ComponentModel;
    using System.Diagnostics;
    using System.Drawing;
    using System.Security;
    using System.Windows.Forms;
    using System.Runtime.InteropServices;
    
    //public enum MaterialScrollOrientation
    //{
    //    Horizontal,
    //    Vertical
    //}

    public enum MaterialScrollBottomRightType
    {
        /// <summary>
        /// min to max of scroll bar  corresponds with 0 to (Height - thumbHeight)
        /// </summary>
        Max,
        /// <summary>
        /// min to max of scroll bar  corresponds with 0 to Height
        /// </summary>
        Not_Max
    }

    [DefaultEvent("Scroll")]
    [DefaultProperty("Value")]
    public class MaterialScrollBar : Control, IMaterialControl
    {

        [Browsable(false)]
        public int Depth { get; set; }
        [Browsable(false)]
        public MaterialSkinManager SkinManager { get { return MaterialSkinManager.Instance; } }
        [Browsable(false)]
        public MouseState MouseState { get; set; }

        protected bool _useAccentColor;

        [Category("Material Skin"), DefaultValue(false), DisplayName("Use Accent Color")]
        public bool UseAccentColor
        {
            get { return _useAccentColor; }
            set { _useAccentColor = value; Invalidate(); }
        }

        [DllImport("user32.dll")]
        public static extern int SendMessage(IntPtr hWnd, int Msg, int wParam, int lParam);

        protected const int SCROLLBAR_DEFAULT_SIZE = 10;

        #region Events

        public event ScrollEventHandler Scroll;

        protected void OnScroll(ScrollEventType type, int oldValue, int newValue, ScrollOrientation orientation)
        {
            if (oldValue != newValue)
            {
                if (ValueChanged != null)
                {
                    ValueChanged(this, _curValue);
                }
            }

            if (Scroll == null)
            {
                return;
            }

            if (orientation == ScrollOrientation.HorizontalScroll)
            {
                if (type != ScrollEventType.EndScroll && isFirstScrollEventHorizontal)
                {
                    type = ScrollEventType.First;
                }
                else if (!isFirstScrollEventHorizontal && type == ScrollEventType.EndScroll)
                {
                    isFirstScrollEventHorizontal = true;
                }
            }
            else
            {
                if (type != ScrollEventType.EndScroll && isFirstScrollEventVertical)
                {
                    type = ScrollEventType.First;
                }
                else if (!isFirstScrollEventHorizontal && type == ScrollEventType.EndScroll)
                {
                    isFirstScrollEventVertical = true;
                }
            }

            Scroll(this, new ScrollEventArgs(type, oldValue, newValue, orientation));
        }

        #endregion

        #region Properties

        private bool isFirstScrollEventVertical = true;
        private bool isFirstScrollEventHorizontal = true;

        protected bool inUpdate;

        protected Rectangle clickedBarRectangle;
        //the part can be dragged
        protected Rectangle thumbRectangle;

        protected bool topBarClicked;
        protected bool bottomBarClicked;
        protected bool thumbClicked;

        protected int thumbWidth = 6;
        protected int thumbHeight;

        protected int thumbBottomLimitBottom;
        protected int thumbBottomLimitTop;
        protected int thumbTopLimit;
        protected int thumbPosition;

        public const int WM_SETREDRAW = 0xb;

        protected int trackPosition;

        private readonly Timer progressTimer = new Timer();

        private int _mouseWheelBarPartitions = 10;
        [Category("Material Skin"), DefaultValue(10)]
        public int MouseWheelBarPartitions 
        {
            get { return _mouseWheelBarPartitions; }
            set
            {
                if (value > 0)
                {
                    _mouseWheelBarPartitions = value;
                }
                else
                {
                    throw new ArgumentOutOfRangeException("value", "MouseWheelBarPartitions has to be greather than zero");
                }
            }
        }

        protected bool isThumbHovered;
        protected bool isHoveredd;
        //private bool isPressed;

        protected bool _useBarColor = false;
        [Category("Material Skin"),DefaultValue(false)]
        public bool UseBarColor
        {
            get { return _useBarColor; }
            set { _useBarColor = value; }
        }

        [Category("Material Skin"), DefaultValue(SCROLLBAR_DEFAULT_SIZE)]
        public int ScrollbarSize
        {
            get { return Orientation == MaterialScrollOrientation.Vertical ? Width : Height; }
            set
            {
                if (Orientation == MaterialScrollOrientation.Vertical)
                    Width = value;
                else
                    Height = value;
            }
        }

        private bool _highlightOnWheel = false;
        [Category("Material Skin"), DefaultValue(false)]
        public bool HighlightOnWheel
        {
            get { return _highlightOnWheel; }
            set { _highlightOnWheel = value; }
        }

        protected MaterialScrollOrientation MaterialOrientation = MaterialScrollOrientation.Vertical;
        protected ScrollOrientation scrollOrientation = ScrollOrientation.VerticalScroll;

        public MaterialScrollOrientation Orientation
        {
            get { return MaterialOrientation; }
            set
            {
                if (value == MaterialOrientation) return;
                MaterialOrientation = value;
                scrollOrientation = value == MaterialScrollOrientation.Vertical ? ScrollOrientation.VerticalScroll : ScrollOrientation.HorizontalScroll;
                Size = new Size(Height, Width);
                SetupScrollBar();
            }
        }

        protected int _minimum = 0;
        [Category("Material Skin"),DefaultValue(0)]
        public int Minimum
        {
            get { return _minimum; }
            set
            {
                if (_minimum == value || value < 0 || value >= _maximum)
                {
                    return;
                }

                _minimum = value;
                if (_curValue < value)
                {
                    _curValue = value;
                }

                if (_largeChange > (_maximum - _minimum))
                {
                    _largeChange = _maximum - _minimum;
                }

                if (_curValue < value)
                {
                    dontUpdateColor = true;
                    Value = value;
                }
                //else
                //{
                //    ChangeThumbPosition(GetThumbPosition());
                //    Refresh();
                //}

                SetupScrollBar();
            }
        }

        protected int _maximum = 100;
        [Category("Material Skin"), DefaultValue(100)]
        public int Maximum
        {
            get { return _maximum; }
            set
            {
                if (value == _maximum || value < 1 || value <= _minimum)
                {
                    return;
                }

                _maximum = value;
                if (_largeChange > (_maximum - _minimum))
                {
                    _largeChange = _maximum - _minimum;
                }
                SetupScrollBar();

                if (_curValue > value)
                {
                    dontUpdateColor = true;
                    Value = _maximum;
                }
                else
                {
                    ChangeThumbPosition(GetThumbPosition());
                    Refresh();
                }
                

            }
        }

        protected int _smallChange = 1;
        [Category("Material Skin"), DefaultValue(1)]
        public int SmallChange
        {
            get { return _smallChange; }
            set
            {
                if (value == _smallChange || value < 1 || value >= _largeChange)
                {
                    return;
                }

                _smallChange = value;
                SetupScrollBar();
            }
        }

        protected int _largeChange = 10;
        [Category("Material Skin"), DefaultValue(10)]
        public int LargeChange
        {
            get { return _largeChange; }
            set
            {
                if (value == _largeChange || value < _smallChange || value < 2)
                {
                    return;
                }

                if (value > (_maximum - _minimum))
                {
                    _largeChange = _maximum - _minimum;
                }
                else
                {
                    _largeChange = value;
                }

                SetupScrollBar();
            }
        }

        protected MaterialScrollBottomRightType _bottomRightType = MaterialScrollBottomRightType.Not_Max;
        [Browsable(false), DefaultValue(MaterialScrollBottomRightType.Not_Max)]
        public MaterialScrollBottomRightType BottomRightType
        {
            get
            {
                return _bottomRightType;
            }
            set
            {
                _bottomRightType = value;
            }

        }

        #region ValueChangeEvent
        // Declare a delegate
        public delegate void ScrollValueChangedDelegate(object sender, int newValue);

        public event ScrollValueChangedDelegate ValueChanged;
        #endregion

        private bool dontUpdateColor = false;


        protected int _curValue = 0;
        [DefaultValue(0)]
        [Browsable(false)]
        public int Value
        {
            get { return _curValue; }

            set
            {
                ProcessValueChange(value);
                //ScrollEventType scrollEventType = ScrollEventType.ThumbPosition;
                //if (_curValue == value)
                //{
                //    return;
                //}
                //else if(value < _minimum)
                //{
                //    scrollEventType = ScrollEventType.First;
                //    _curValue = _minimum;
                //}
                //else if(value > _maximum)
                //{
                //    scrollEventType = ScrollEventType.Last;
                //    _curValue = _maximum;
                //}
                //else
                //{
                //    _curValue = value;
                //}

                //ChangeThumbPosition(GetThumbPosition());

                //OnScroll(scrollEventType, -1, value, scrollOrientation);

                //if (!dontUpdateColor && _highlightOnWheel)
                //{
                //    if (!isThumbHovered)
                //        isThumbHovered = true;

                //    if (autoHoverTimer == null)
                //    {
                //        autoHoverTimer = new Timer();
                //        autoHoverTimer.Interval = 1000;
                //        autoHoverTimer.Tick += new EventHandler(autoHoverTimer_Tick);
                //        autoHoverTimer.Start();
                //    }
                //    else
                //    {
                //        autoHoverTimer.Stop();
                //        autoHoverTimer.Start();
                //    }
                //}
                //else
                //{
                //    dontUpdateColor = false;
                //}

                //Refresh();
            }
        }

        private void autoHoverTimer_Tick(object sender, EventArgs e)
        {
            isThumbHovered = false;
            Invalidate();
            autoHoverTimer.Stop();
        }

        private Timer autoHoverTimer = null;

        #endregion

        public MaterialScrollBar()
        {
            SetStyle(ControlStyles.OptimizedDoubleBuffer |
                ControlStyles.OptimizedDoubleBuffer |
                     ControlStyles.ResizeRedraw |
                     ControlStyles.Selectable |
//                     ControlStyles.AllPaintingInWmPaint |
                     ControlStyles.SupportsTransparentBackColor |
                     ControlStyles.UserPaint, true);

            Width = SCROLLBAR_DEFAULT_SIZE;
            Height = 200;

            UseAccentColor = false;

            SetupScrollBar();

            progressTimer.Interval = 20;
            progressTimer.Tick += ProgressTimerTick;
        }

        public MaterialScrollBar(MaterialScrollOrientation orientation)
            : this()
        {
            Orientation = orientation;
        }

        public MaterialScrollBar(MaterialScrollOrientation orientation, int width)
            : this(orientation)
        {
            Width = width;
        }

        public bool HitTest(Point point)
        {
            return thumbRectangle.Contains(point);
        }

        #region Update Methods

        [SecuritySafeCritical]
        public void BeginUpdate()
        {
            SendMessage(Handle, WM_SETREDRAW, 0, 0);
            inUpdate = true;
        }

        [SecuritySafeCritical]
        public void EndUpdate()
        {
            SendMessage(Handle, WM_SETREDRAW, 1, 0);
            inUpdate = false;
            SetupScrollBar();
            Refresh();
        }

        #endregion

        #region Paint Methods


        protected override void OnPaintBackground(PaintEventArgs e)
        {
            try
            {
                e.Graphics.Clear(Parent.BackColor);
            }
            catch (Exception ex)
            {
                Trace.WriteLine(ex);
                Invalidate();
            }
        }

        protected override void OnPaint(PaintEventArgs e)
        {
            DrawScrollBar(e.Graphics, MaterialSkinManager.Instance.CardsColor, SkinManager.SwitchOffTrackColor, _useAccentColor ? MaterialSkinManager.Instance.ColorScheme.AccentColor : MaterialSkinManager.Instance.ColorScheme.PrimaryColor);
        }

        protected virtual void DrawScrollBar(Graphics g, Color backColor, Color thumbColor, Color barColor)
        {
            if (_useBarColor)
            {
                using (SolidBrush b = new SolidBrush(barColor))
                {
                    g.FillRectangle(b, ClientRectangle);
                    
                }
            }

            using (SolidBrush b = new SolidBrush(backColor))
            {
                Rectangle thumbRect = new Rectangle(thumbRectangle.X - 1, thumbRectangle.Y - 1, thumbRectangle.Width + 2, thumbRectangle.Height + 2);
                g.FillRectangle(b, thumbRect);
            }

            using (SolidBrush b = new SolidBrush(isThumbHovered || thumbClicked ? barColor : thumbColor))
            {
                g.FillRectangle(b, thumbRectangle);
            }
        }

        #endregion

        #region Focus Methods

        protected override void OnGotFocus(EventArgs e)
        {
            Invalidate();

            base.OnGotFocus(e);
        }

        protected override void OnLostFocus(EventArgs e)
        {
            isThumbHovered = false;
            //isPressed = false;
            Invalidate();

            base.OnLostFocus(e);
        }

        protected override void OnEnter(EventArgs e)
        {
            Invalidate();

            base.OnEnter(e);
        }

        protected override void OnLeave(EventArgs e)
        {
            isThumbHovered = false;
            //isPressed = false;
            Invalidate();

            base.OnLeave(e);
        }

        #endregion

        #region Mouse Methods

        protected override void OnMouseWheel(MouseEventArgs e)
        {
            base.OnMouseWheel(e);

            int v = e.Delta / 120 * (_maximum - _minimum) / _mouseWheelBarPartitions;

            if (Orientation == MaterialScrollOrientation.Vertical)
            {
                Value -= v;
            }
            else
            {
                Value += v;
            }
        }

        protected override void OnMouseDown(MouseEventArgs e)
        {

            if (e.Button == MouseButtons.Left)
            {
                //isPressed = true;
                Invalidate();
            }

            base.OnMouseDown(e);

            Focus();

            if (e.Button == MouseButtons.Left)
            {

                Point mouseLocation = e.Location;

                if (thumbRectangle.Contains(mouseLocation))
                {
                    thumbClicked = true;
                    thumbPosition = MaterialOrientation == MaterialScrollOrientation.Vertical ? mouseLocation.Y - thumbRectangle.Y : mouseLocation.X - thumbRectangle.X;

                    Invalidate(thumbRectangle);
                }
                else
                {
                    trackPosition = MaterialOrientation == MaterialScrollOrientation.Vertical ? mouseLocation.Y : mouseLocation.X;

                    if (trackPosition < (MaterialOrientation == MaterialScrollOrientation.Vertical ? thumbRectangle.Y : thumbRectangle.X) && trackPosition > thumbTopLimit)
                    {
                        topBarClicked = true;
                    }
                    else if(trackPosition > (MaterialOrientation == MaterialScrollOrientation.Vertical ? thumbRectangle.Bottom: thumbRectangle.Right) && trackPosition < thumbBottomLimitBottom)
                    {
                        bottomBarClicked = true;
                    }
     
                    ProgressThumb(true);
                }
            }
            else if (e.Button == MouseButtons.Right)
            {
                trackPosition = MaterialOrientation == MaterialScrollOrientation.Vertical ? e.Y : e.X;
            }

        }

        protected override void OnMouseUp(MouseEventArgs e)
        {
            //isPressed = false;

            base.OnMouseUp(e);

            if (e.Button == MouseButtons.Left)
            {
                if (thumbClicked)
                {
                    thumbClicked = false;
                    OnScroll(ScrollEventType.EndScroll, -1, _curValue, scrollOrientation);
                    //function Invalidate() is placed inner for best, each if has a Invalidate() function, means that 
                    //no if no Invalidate() function
                    Invalidate();
                }
                else if (topBarClicked)
                {
                    topBarClicked = false;
                    StopTimer();
                    Invalidate();
                }
                else if (bottomBarClicked)
                {
                    bottomBarClicked = false;
                    StopTimer();
                    Invalidate();
                }
            }
        }

        protected override void OnMouseEnter(EventArgs e)
        {
            if(thumbRectangle.Contains(this.PointToClient(Control.MousePosition)))
            {
                isThumbHovered = true;
                Invalidate();
            }

            base.OnMouseEnter(e);
        }

        protected override void OnMouseLeave(EventArgs e)
        {
            isThumbHovered = false;
            Invalidate();

            base.OnMouseLeave(e);

            ResetScrollStatus();
        }

        protected override void OnMouseMove(MouseEventArgs e)
        {
            base.OnMouseMove(e);

            if (e.Button == MouseButtons.Left)
            {
                if (thumbClicked)
                {
                    int oldScrollValue = _curValue;
                    //mouse location
                    int pos = MaterialOrientation == MaterialScrollOrientation.Vertical ? e.Location.Y : e.Location.X;
                    int thumbSize = MaterialOrientation == MaterialScrollOrientation.Vertical ? (pos / Height) / thumbHeight : (pos / Width) / thumbWidth;
                    if (_bottomRightType == MaterialScrollBottomRightType.Max)
                    {
                        thumbSize = MaterialOrientation == MaterialScrollOrientation.Vertical ? thumbHeight : thumbWidth;
                    }
                    //just pos in a small area
                    if (pos <= (thumbTopLimit + thumbPosition))
                    {
                        ChangeThumbPosition(thumbTopLimit);
                        _curValue = _minimum;
                        Invalidate();
                    }
                    else if (pos >= (thumbBottomLimitTop + thumbPosition))
                    {
                        ChangeThumbPosition(thumbBottomLimitTop);
                        if (_bottomRightType == MaterialScrollBottomRightType.Max)
                            _curValue = _maximum;
                        else
                            _curValue = _maximum - _largeChange + 1;
                        Invalidate();
                    }
                    else
                    {
                        //pos - thumbPosition = thumbRectangle's location
                        ChangeThumbPosition(pos - thumbPosition);

                        int pixelRange, thumbPos;

                        if (Orientation == MaterialScrollOrientation.Vertical)
                        {
                            pixelRange = Height - thumbSize;
                            thumbPos = thumbRectangle.Y;
                        }
                        else
                        {
                            pixelRange = Width - thumbSize;
                            thumbPos = thumbRectangle.X;
                        }

                        float perc = 0f;

                        if (pixelRange != 0)
                        {
                            perc = (thumbPos) / (float)pixelRange;
                        }

                        _curValue = Convert.ToInt32((perc * (_maximum - _minimum)) + _minimum);
                    }

                    if (oldScrollValue != _curValue)
                    {
                        OnScroll(ScrollEventType.ThumbTrack, oldScrollValue, _curValue, scrollOrientation);
                        Refresh();
                    }
                }
            }
            //else if (!ClientRectangle.Contains(e.Location))
            //{
            //    ResetScrollStatus();
            //}
            else if (e.Button == MouseButtons.None)
            {
                if (thumbRectangle.Contains(e.Location))
                {
                    isThumbHovered = true;
                    Invalidate(thumbRectangle);
                }
                else if (ClientRectangle.Contains(e.Location))
                {
                    isThumbHovered = false;
                    Invalidate();
                }
                else if (!ClientRectangle.Contains(e.Location))
                {
                    ResetScrollStatus();
                }
            }

        }

        #endregion

        #region Keyboard Methods

        protected override void OnKeyDown(KeyEventArgs e)
        {
            Console.WriteLine("scroll bar OnKeyDown in focused=" + this.Focused);
            //isThumbHovered = true;
            //isPressed = true;
            Invalidate();

            base.OnKeyDown(e);
            Console.WriteLine("scroll bar OnKeyDown out focused=" + this.Focused);
        }

        protected override void OnKeyUp(KeyEventArgs e)
        {
            Console.WriteLine("scroll bar OnKeyUp in focused=" + this.Focused);
            //isThumbHovered = false;
            //isPressed = false;
            Invalidate();

            base.OnKeyUp(e);
            Console.WriteLine("scroll bar OnKeyUp out focused=" + this.Focused);
        }

        #endregion

        #region Management Methods
        protected void ProcessValueChange(int value)
        {
            ScrollEventType scrollEventType = ScrollEventType.ThumbPosition;
            if (_curValue == value)
            {
                return;
            }
            else if (value < _minimum)
            {
                scrollEventType = ScrollEventType.First;
                _curValue = _minimum;
            }
            else if (value > _maximum)
            {
                scrollEventType = ScrollEventType.Last;
                _curValue = _maximum;
            }
            else
            {
                _curValue = value;
            }

            ChangeThumbPosition(GetThumbPosition());

            OnScroll(scrollEventType, -1, value, scrollOrientation);

            if (!dontUpdateColor && _highlightOnWheel)
            {
                if (!isThumbHovered)
                    isThumbHovered = true;

                if (autoHoverTimer == null)
                {
                    autoHoverTimer = new Timer();
                    autoHoverTimer.Interval = 1000;
                    autoHoverTimer.Tick += new EventHandler(autoHoverTimer_Tick);
                    autoHoverTimer.Start();
                }
                else
                {
                    autoHoverTimer.Stop();
                    autoHoverTimer.Start();
                }
            }
            else
            {
                dontUpdateColor = false;
            }

            Refresh();
        }


        protected override void SetBoundsCore(int x, int y, int width, int height, BoundsSpecified specified)
        {
            base.SetBoundsCore(x, y, width, height, specified);

            if (DesignMode)
            {
                SetupScrollBar();
            }
        }

        protected override void OnSizeChanged(EventArgs e)
        {
            base.OnSizeChanged(e);
            SetupScrollBar();
        }

        //protected override void OnPreviewKeyDown(PreviewKeyDownEventArgs e)
        //{

        //    if (Orientation == MaterialScrollOrientation.Horizontal)
        //    {
        //        if (e.KeyCode == Keys.Left || e.KeyCode == Keys.Right)
        //            //IsInputKey = true will not be processed in the ProcessDialogKey
        //            e.IsInputKey = true;
        //    }
        //    else
        //    {
        //        if (e.KeyCode == Keys.Down || e.KeyCode == Keys.Up)
        //            e.IsInputKey = true;
        //    }

        //    base.OnPreviewKeyDown(e);
        //}

        //protected override bool ProcessDialogKey(Keys keyData)
        //{
        //    Keys keyUp = Keys.Up;
        //    Keys keyDown = Keys.Down;

        //    if (Orientation == MaterialScrollOrientation.Horizontal)
        //    {
        //        keyUp = Keys.Left;
        //        keyDown = Keys.Right;
        //    }

        //    if (keyData == keyUp)
        //    {
        //        //Value -= _smallChange;
        //        ProcessValueChange(_curValue - _smallChange);

        //        return true;
        //    }

        //    if (keyData == keyDown)
        //    {
        //        //Value += _smallChange;
        //        ProcessValueChange(_curValue + _smallChange);

        //        return true;
        //    }

        //    if (keyData == Keys.PageUp)
        //    {
        //        //Value = GetValue(false, true);
        //        ProcessValueChange(GetValue(false, true));

        //        return true;
        //    }

        //    if (keyData == Keys.PageDown)
        //    {
        //        if (_curValue + _largeChange > _maximum)
        //        {
        //            //Value = _maximum;
        //            ProcessValueChange(_maximum);
        //        }
        //        else
        //        {
        //            //Value += _largeChange;
        //            ProcessValueChange(_curValue + _largeChange);
        //        }

        //        return true;
        //    }

        //    if (keyData == Keys.Home)
        //    {
        //        //Value = _minimum;
        //        ProcessValueChange(_minimum);
        //        return true;
        //    }

        //    if (keyData == Keys.End)
        //    {
        //        //Value = _maximum;
        //        ProcessValueChange(_maximum);
        //        return true;
        //    }

        //    return base.ProcessDialogKey(keyData);
        //}

        protected override void OnEnabledChanged(EventArgs e)
        {
            base.OnEnabledChanged(e);
            Invalidate();
        }

        protected virtual void SetupScrollBar()
        {
            
            if (inUpdate) return;

            if (Orientation == MaterialScrollOrientation.Vertical)
            {
                thumbWidth = Width > 0 ? Width : 10;
                thumbHeight = GetThumbSize();

                clickedBarRectangle = ClientRectangle;
                clickedBarRectangle.Inflate(-1, -1);

                thumbRectangle = new Rectangle(ClientRectangle.X, ClientRectangle.Y, thumbWidth, thumbHeight);

                thumbPosition = thumbRectangle.Height / 2;
                thumbBottomLimitBottom = ClientRectangle.Bottom;
                thumbBottomLimitTop = thumbBottomLimitBottom - thumbRectangle.Height;
                thumbTopLimit = ClientRectangle.Y;
            }
            else
            {
                thumbHeight = Height > 0 ? Height : 10;
                thumbWidth = GetThumbSize();

                clickedBarRectangle = ClientRectangle;
                clickedBarRectangle.Inflate(-1, -1);

                thumbRectangle = new Rectangle(ClientRectangle.X, ClientRectangle.Y, thumbWidth, thumbHeight);

                thumbPosition = thumbRectangle.Width / 2;
                thumbBottomLimitBottom = ClientRectangle.Right;
                thumbBottomLimitTop = thumbBottomLimitBottom - thumbRectangle.Width;
                thumbTopLimit = ClientRectangle.X;
            }

            ChangeThumbPosition(GetThumbPosition());

            Refresh();
        }

        protected virtual void ResetScrollStatus()
        {
            bottomBarClicked = topBarClicked = false;

            StopTimer();
            Refresh();
        }

        private void ProgressTimerTick(object sender, EventArgs e)
        {
            ProgressThumb(true);
        }

        protected int GetValue(bool smallIncrement, bool up)
        {
            int newValue;

            if (up)
            {
                newValue = _curValue - (smallIncrement ? _smallChange : _largeChange);

                if (newValue < _minimum)
                {
                    newValue = _minimum;
                }
            }
            else
            {
                newValue = _curValue + (smallIncrement ? _smallChange : _largeChange);

                if (newValue > _maximum)
                {
                    newValue = _maximum;
                }
            }

            return newValue;
        }

        protected virtual int GetThumbPosition()
        {
            int pixelRange;

            if (_curValue == _minimum)
                return thumbTopLimit;
            else if (_curValue == _maximum && _bottomRightType == MaterialScrollBottomRightType.Max)
                return thumbBottomLimitTop;
            else if(_curValue >= _maximum - _largeChange + 1 && _bottomRightType == MaterialScrollBottomRightType.Not_Max)
            {
                _curValue = _maximum - _largeChange + 1;
                return thumbBottomLimitTop;
            }
            else
            {
                if (thumbHeight == 0 || thumbWidth == 0)
                {
                    return 0;
                }
                //don't know why this thumbSize here,
                //is just bias?
                int thumbSize = MaterialOrientation == MaterialScrollOrientation.Vertical ? (thumbPosition / Height) / thumbHeight : (thumbPosition / Width) / thumbWidth;

                
                if(_bottomRightType == MaterialScrollBottomRightType.Max)
                {
                    thumbSize = MaterialOrientation == MaterialScrollOrientation.Vertical ? thumbHeight : thumbWidth;
                }

                if (Orientation == MaterialScrollOrientation.Vertical)
                {
                    pixelRange = Height - thumbSize;
                }
                else
                {
                    pixelRange = Width - thumbSize;
                }

                int realRange = _maximum - _minimum;
                float perc = 0f;

                if (realRange != 0)
                {
                    perc = (_curValue - (float)_minimum) / realRange;
                }
                //transfer value to control's pixel location
                return thumbTopLimit + Convert.ToInt32((perc * pixelRange));
                //return Math.Max(thumbTopLimit, Math.Min(thumbBottomLimitTop, Convert.ToInt32((perc * pixelRange))));
            }

        }

        protected virtual int GetThumbSize()
        {
            int trackSize =
                MaterialOrientation == MaterialScrollOrientation.Vertical ?
                    Height : Width;

            if (_maximum == 0 || _largeChange == 0)
            {
                return trackSize;
            }

            float newThumbSize = (_largeChange * (float)trackSize) / (_maximum - _minimum);

            return Convert.ToInt32(Math.Min(trackSize, Math.Max(newThumbSize, 10f)));
        }

        protected void EnableTimer()
        {
            if (!progressTimer.Enabled)
            {
                progressTimer.Interval = 600;
                progressTimer.Start();
            }
            else
            {
                progressTimer.Interval = 10;
            }
        }

        protected void StopTimer()
        {
            progressTimer.Stop();
        }

        protected void ChangeThumbPosition(int position)
        {
            if (Orientation == MaterialScrollOrientation.Vertical)
            {
                thumbRectangle.Y = position;
            }
            else
            {
                thumbRectangle.X = position;
            }
        }
        ///// <summary>
        ///// 
        ///// </summary>
        ///// <param name="mouseLocation">client control mouse location, not screen mouse location</param>
        //protected virtual void ChangeTrackPosition(Point mouseLocation)
        //{
        //    trackPosition = MaterialOrientation == MaterialScrollOrientation.Vertical ? mouseLocation.Y : mouseLocation.X;
        //}

        protected virtual void ProgressThumb(bool enableTimer)
        {
            int scrollOldValue = _curValue;
            ScrollEventType type = ScrollEventType.First;
            int thumbSize, thumbPos;

            if (Orientation == MaterialScrollOrientation.Vertical)
            {
                thumbPos = thumbRectangle.Y;
                thumbSize = thumbRectangle.Height;
            }
            else
            {
                thumbPos = thumbRectangle.X;
                thumbSize = thumbRectangle.Width;
            }

            if ((bottomBarClicked && (thumbPos + thumbSize) < trackPosition))
            {
                type = ScrollEventType.LargeIncrement;

                _curValue = GetValue(false, false);

                if (_curValue == _maximum)
                {
                    //ChangeThumbPosition(thumbBottomLimitTop);

                    type = ScrollEventType.Last;
                }
                //else
                //{
                //    ChangeThumbPosition(Math.Min(thumbBottomLimitTop, GetThumbPosition()));
                //}
                ChangeThumbPosition(GetThumbPosition());
            }
            else if ((topBarClicked && thumbPos > trackPosition))
            {
                type = ScrollEventType.LargeDecrement;

                _curValue = GetValue(false, true);

                if (_curValue == _minimum)
                {
                    //ChangeThumbPosition(thumbTopLimit);

                    type = ScrollEventType.First;
                }
                //else
                //{
                //    ChangeThumbPosition(Math.Max(thumbTopLimit, GetThumbPosition()));
                //}
                ChangeThumbPosition(GetThumbPosition());
            }

            if (scrollOldValue != _curValue)
            {
                OnScroll(type, scrollOldValue, _curValue, scrollOrientation);

                Invalidate();

                if (enableTimer)
                {
                    EnableTimer();
                }
            }
        }

        #endregion
    }
}
